package com.ss.android.auto.launch.tasks.collector

import android.os.Process
import android.util.Log
import com.bytedance.common.utility.concurrent.ThreadPlus
import com.ss.android.auto.optimize.serviceapi.IJatoService
import com.ss.android.auto.servicemanagerwrapper.AutoServiceManager
import java8.util.concurrent.CompletableFuture
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CountDownLatch
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.ThreadFactory
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean

/**
 *  @author zhongxinyuan @ ByteDance Inc
 *  @since   2023/2/1
 */
abstract class AsyncThreadTaskCollector : TaskCollector() {

    private var completeFlag: CountDownLatch? = null

    override fun executeTasks(tasksWrapper: List<() -> Unit>) {
        completeFlag = CountDownLatch(1)
        ThreadPlus.submitRunnable {
            markGroupStart()
            val list = tasksWrapper.map { task ->
                CompletableFuture.runAsync(
                    Runnable {
//                            Safe.call { applyThreadBoost() }
                        task.invoke()
                    },
                    threadPoolExecutor
                )
            }.toList().toTypedArray<CompletableFuture<Void>>()

            CompletableFuture.allOf(*list).join()
            markGroupEnd()
            completeFlag?.countDown()
        }
    }


    fun waitComplete() {
        completeFlag?.await()
    }

    companion object {

        val cpuInfoReady: AtomicBoolean = AtomicBoolean(false)
        private val boostTidList: MutableMap<Int, Boolean> = ConcurrentHashMap()

        private fun applyThreadBoost() {
            val myTid = Process.myTid()
            if (cpuInfoReady.get()) {
                if (!boostTidList.containsKey(myTid)) {
                    AutoServiceManager.getService2(IJatoService::class.java)?.tryBindBigCore(myTid)
                    AutoServiceManager.getService2(IJatoService::class.java)
                        ?.trySetPriority(myTid, -20)
                    boostTidList[myTid] = true
                    Log.d("LaunchTaskStarter", "tryBindBigCore:$myTid")
                }
            } else {
                Log.d("LaunchTaskStarter", "tryBindBigCore:$myTid, but cpu info is not ready")
            }
        }

        private val threadPoolExecutor = ThreadPoolExecutor(
            1,
            1,
            4,
            TimeUnit.SECONDS,
            LinkedBlockingQueue(),
            ThreadFactory { r ->
                Thread({
                    r?.run()
                }, "BigCoreThread")
            },
            ThreadPoolExecutor.AbortPolicy()
        )

    }
}

